from new_rmasm.temp_code import *
from new_rmasm.exceptions import *

if False:
    from new_rmasm.lexer import *


def result_code_line_num(result: List[str]) -> int:
    res = 0
    for r in result:
        if not r.startswith('#'):
            res += 1
    return res


class TCTranslator:
    def __init__(self, tcs: List[TempCode]):
        self.tcs = tcs

        self.before_tags = []
        self.after_tags = []

    def error(self, token: 'LexToken', message: str) -> RMASMError:
        return RTranslateError(token.source, token.line_num, message)

    def after_tag_num(self, name: str) -> int:
        res = 0
        for t in self.after_tags:
            if t[0] == name:
                res += 1
        return res

    def before_tag_num(self, name: str) -> int:
        res = 0
        for t in self.before_tags:
            if t[0] == name:
                res += 1
        return res

    def find_tag_num(self, from_token: 'LexToken', dir: str, name: str) -> int:
        if dir == '+':
            if not self.after_tag_num(name):
                raise self.error(from_token, f"向后的方向不存在标签 {name}")
            for i in self.after_tags:
                if i[0] == name:
                    return i[1]
        if dir == '-':
            if not self.before_tag_num(name):
                raise self.error(from_token, f"向前的方向不存在标签 {name}")
            for i in self.before_tags:
                if i[0] == name:
                    return i[1]
        bn = self.before_tag_num(name)
        an = self.after_tag_num(name)
        nums = bn + an
        if nums == 0:
            raise self.error(from_token, f'找不到标签 {name}')
        if nums > 1:
            raise self.error(from_token, f'拥有重复的标签，可以使用 + 和 - 符号指明标号的方向。')
        target = self.before_tags if bn else self.after_tags
        for i in target:
            if i[0] == name:
                return i[1]

    def translate(self) -> str:
        result = []
        line_num = 0
        for tc in self.tcs:
            if tc.step_line:
                line_num += 1
            f = tc.codes[0]
            if isinstance(f, TagTCToken):
                self.after_tags.append([f.name, line_num])

        for tc in self.tcs:
            line = []
            for code in tc.codes:
                if isinstance(code, str):
                    line.append(code)
                elif isinstance(code, TagTCToken):
                    a = self.after_tags[0]
                    self.before_tags.insert(0, a)
                    del self.after_tags[0]
                elif isinstance(code, TagNumTCToken):
                    if code.direction or code.target:
                        line.append(
                            str(self.find_tag_num(tc.token, code.direction,
                                                  code.target))
                        )
                    else:
                        line.append(str(result_code_line_num(result)))
                elif isinstance(code, EvalTCToken):
                    line.append(str(eval(code.expr, {}, {})))
            if tc.has_result:
                result.append(' '.join(line))
        return '\n'.join(result)
